#include <string>
#include <iostream>
#include <sstream>

#include "hashtbl.h"
#include "EncodedStructs.h"

using std::cout;
using std::endl;
using std::cin;
using std::string;
using std::hex;

int setRegisters(INSTU *u, Decoded d, HashTbl *tbl)
{
	numbers *p=NULL;

	/* RTYPE CASING */
	if(u->R.opcode==0)
	{
		/*rd, rt, fd*/
		if(u->R.funct==0 || u->R.funct==2 || u->R.funct==3) 
		{
			p = (numbers *)tbl->get(&d.reg1[0]);
			u->R.rd = p->reg;
			p=(numbers *)tbl->get(&d.reg2[0]);
			u->R.rt = p->reg;
			p=(numbers *)tbl->get(&d.reg3[0]);
			u->R.fd = p->reg;
			return 3;
		}

		/*rd, rt, rs*/
		else if(u->R.funct==4 || u->R.funct==6 || u->R.funct==7)
		{
			p = (numbers *)tbl->get(&d.reg1[0]);
			u->R.rd = p->reg;
			p=(numbers *)tbl->get(&d.reg2[0]);
			u->R.rt = p->reg;
			p=(numbers *)tbl->get(&d.reg3[0]);
			u->R.rs = p->reg;
			return 3;
		}

		/*rd, rs*/
		else if(u->R.funct==9)
		{
			p = (numbers *)tbl->get(&d.reg1[0]);
			u->R.rd = p->reg;
			p = (numbers *)tbl->get(&d.reg2[0]);
			u->R.rs = p->reg;
			return 2;
		}

		/*syscall, break, sync*/
		else if(u->R.funct==12 || u->R.funct==13 || u->R.funct==15)
		{
			return 0;
			/*Not sure about sync. Can't find the format*/
		}
	
		/*rd, rs, rt */
		else if( (u->R.funct >=32 && u->R.funct <= 47) || u->R.funct==10 || u->R.funct==11)
		{
			p = (numbers *)tbl->get(&d.reg1[0]);
			u->R.rd = p->reg;
			p = (numbers *)tbl->get(&d.reg2[0]);
			u->R.rs = p->reg;
			p = (numbers *)tbl->get(&d.reg3[0]);
			u->R.rt = p->reg;
			return 3;
		}

		/*rd*/
		else if(u->R.funct==16 || u->R.funct==18)
		{
			p = (numbers *)tbl->get(&d.reg1[0]);
			u->R.rd = p->reg;
			return 1;
		}

		/*rs*/
		else if(u->R.funct==8 || u->R.funct==17 || u->R.funct==19)
		{
			p = (numbers *)tbl->get(&d.reg1[0]);
			u->R.rs = p->reg;
			return 1;
		}

		/*rs, rt*/
		else if(u->R.funct==24 || u->R.funct==25 || (u->R.funct>=48 && u->R.funct<=54) )
		{
			p = (numbers *)tbl->get(&d.reg1[0]);
			u->R.rs = p->reg;
			p = (numbers *)tbl->get(&d.reg2[0]);
			u->R.rt = p->reg;
			return 2;
		}

	}/*End of RTYPE if*/

	/*JTYPE CASES*/
	else if(u->R.opcode==2 || u->R.opcode==3)
	{
		//Dont know how to translate labels yet. Maybe someone else's job?
		//u.J.target = getLabel(d.reg1);
		return 1;
	}/*END OF JTYPE CASES*/

	/*FLOATING POINT REGISTERS*/
	else if(u->R.opcode == 16 || u->R.opcode == 17 || u->R.opcode == 18 || u->R.opcode == 19)
	{
        if( (u->R.funct == 5)  || (u->R.funct == 14) || (u->R.funct == 33) || (u->R.funct == 32) ||
			(u->R.funct == 36) || (u->R.funct == 15) || (u->R.funct == 6)  || (u->R.funct == 7)  || 
			(u->R.funct == 12) || (u->R.funct == 4)  || (u->R.funct == 13) )
		{
			p = (numbers *)tbl->get(&d.reg1[0]);
			u->R.fd = p->reg; 
			p = (numbers *)tbl->get(&d.reg2[0]);
			u->R.rd = p->reg; 
			return 2;
	    }

		else if(u->R.funct == 0 || u->R.funct == 3 || u->R.funct == 2 || u->R.funct == 1 || u->R.funct == 19 || u->R.funct == 18)
		{
			p = (numbers *)tbl->get(&d.reg1[0]);
			u->R.fd = p->reg; 
			p = (numbers *)tbl->get(&d.reg2[0]);
			u->R.rd = p->reg; 
			p = (numbers *)tbl->get(&d.reg3[0]);
			u->R.rt = p->reg; 
			return 3;
		}
		else if(u->R.funct == 24)
		{
			return 0;
		}
	}
		
	/* None of the cases! */
	else
	{
		printf("Uh Oh!\n");
		return 10;
	}
}

/*void something(vector<Decoded> &v)
{
	cout<<"here: "<<v[0].opcode<<endl;
}*/


int main()
{
        HashTbl *tbl, *RegTbl;

        string str;
        INSTU *p;
		INSTU *u;
        numbers *poin=NULL;
		u = new INSTU;
		Decoded d;
		d.opcode="and";
		d.reg1 = "$s1";
		d.reg2 = "$s1";
		d.reg3 = "$zero";

        if(!(tbl=new HashTbl(16, NULL))) {
                fprintf(stderr, "ERROR: hashtbl_create() failed\n");
                exit(EXIT_FAILURE);
        }

        if(!(RegTbl=new HashTbl(16, NULL))) {
                fprintf(stderr, "ERROR: hashtbl_create() failed\n");
                exit(EXIT_FAILURE);
        }

        HashOpcode(tbl);
        HashRegister(RegTbl);

		p=(INSTU *)tbl->get(&d.opcode[0]);
		if(p) cout<<p->R.opcode<<endl;

		setRegisters(p, d, RegTbl);
		cout<<hex<<p->instruction<<endl;

       // while(str != "exit")
        //{
                /*cout<<"Enter a test case for the opcode!..";
                cin>>str;
                p=(INSTU *)tbl->get(&str[0]);
                if(p)
                {
                        cout<<"Here are your numbers:"<<endl;
                        cout<<"u.R.opcode="<<p->R.opcode<<endl;
                        cout<<"u.R.funct="<<p->R.funct<<endl;
                        cout<<"u.R.rs="<<p->R.rs<<endl;
                        cout<<"I hope you're happy with the results of your hard work! ;)"<<endl;
                }
                else cout<<"oops.. no match. Or you are exiting."<<endl;*/

                /*cout<<"Enter a test case for the register...";
                cin>>str;
                poin=(numbers *)RegTbl->get(&str[0]);
                if(poin)
                {
                        cout<<"Here's your number: "<<poin->reg<<endl;
                }
                else cout<<"oops.. no match. Or you are exiting."<<endl;*/

				
				

        //}

        /*
        vector<Decoded> DeInstructions; 

        INSTU u;
        INSTU *p;

        Decoded I;
        I.opcode="add";
        I.reg1="$21";
        DeInstructions.push_back(I);

        u.J.opcode=23;
        u.D.pad=17999073;

        
        
        EnInsts.push_back(u.instruction);
        cout<<EnInsts[0]<<endl;
        else cout<<I.opcode<<endl;

        numbers n, a, *p;
        n.op=0;
        n.funct=32;


        
        tbl->insert("add", &u);
        p=(INSTU *)tbl->get(&I.opcode[0]);
        p->J.target=17999073;
        if(p) cout<<"here I am: "<<p->instruction<<endl;
        else cout<<"not match"<<endl;


        a.op=2;
        a.funct=30;

        tbl->insert("add", &a);

        p=(numbers *)tbl->get("mfc0");
        if(!p) printf("No match\n");
        else printf("Mfc0: %d, %d\n", p->funct, p->op);


        p=(numbers *)tbl->get("add");
        if(!p) printf("No match\n");
        else printf("Add: %d, %d\n", p->funct, p->op);
        //if(p->funct==3) printf("It equals\n");
        a.op=50;
        a.funct=50;


        delete(tbl);*/
        return 0;
}
